﻿using System;
using System.Xml;
using System.Collections.ObjectModel;

namespace NBPEx
{
    public abstract class ExchangeTableBase<T>: IDisposable
    {
        private XmlTextReader reader;
        private ExchangeTable tableID;
        private string description;
        /// <summary>
        /// Identyfikator tabeli
        /// </summary>
        public ExchangeTable TableID
        {
            get { return tableID; }
            set { tableID = value; }
        }
        /// <summary>
        /// Opis tabeli
        /// </summary>
        public string Description
        {
            get { return description; }
            set { description = value; }
        }
        /// <summary>
        /// Kolekcja pozycji tabel kursów walut
        /// </summary>
//        private ExchangeTablePositionsCollection<T> Positions;
        public Collection<T> Positions;

        private string numerTabeli;
        private string dataPublikacji;

        public DateTime DownloadDate { get; set; }

        protected ExchangeTableBase(ExchangeTable table, string description = "")
        {            
            Positions = new Collection<T>();
            TableID = table;
            Description = description;
        }

        public T this[int index]
        {
            get { return ((T)(Positions[index])); }
            set { Positions[index] = value; }
        }

        public void ReadTable(DateTime date)
        {
            try
            {
                string link = ExchangeListReader.ExchangeTableLink(TableID, date);
                if (String.IsNullOrEmpty(link))
                {
                    System.Windows.Forms.MessageBox.Show("Nie znaleziono kursów walut dla tabeli " + TableID.ToString() + " z dnia " + date.ToShortDateString(), "Brak danych", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
                    return;
                }
                reader = new XmlTextReader(link);
                ParseHeader(reader);
                ParseAdditionalInfo(reader);
                ParseBody(reader);
                DownloadDate = DateTime.Now;
            }
            catch (Exception E)
            {
                System.Windows.Forms.MessageBox.Show(E.Message, "Wyjątek", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
            }
        }

        public void ReadTableRange(DateTime dateFrom, DateTime dateTo)
        {
            if (dateFrom.CompareTo(dateTo) > 0)
            {
                System.Windows.Forms.MessageBox.Show("Data od: " + dateFrom.ToLongDateString() + " musi być wcześniejsza od daty do: " + dateTo.ToLongDateString(), "Wyjątek", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                return;
            }
            while (dateFrom.CompareTo(dateTo) <= 0)
            {
                ReadTable(dateFrom);
                dateFrom = dateFrom.AddDays(1);
            }
        }

        protected abstract T ParsePositionElement(XmlReader node, string numerTabeli, string dataPublikacji);

        protected virtual void ParseAdditionalInfo(XmlReader reader) { }

        private void ParseHeader(XmlTextReader reader)
        {
            numerTabeli = "";
            dataPublikacji = "";
            while (reader.Read() & !reader.Name.Equals("pozycja"))
            {
                switch (reader.Name)
                {
                    case "tabela_kursow": break;
                    case "numer_tabeli": numerTabeli = reader.ReadString(); break;
                    case "data_publikacji": dataPublikacji = reader.ReadString(); break;
                }
            }
        }

        private void ParseBody(XmlTextReader reader)
        {
            while (reader.ReadToFollowing("pozycja"))
            {
                Positions.Add(ParsePositionElement(reader.ReadSubtree(), numerTabeli, dataPublikacji));
            }
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                reader.Close();
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}
